#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdbool.h>
#include <errno.h>

// ====================== 配置常量 ======================
#define MAX_STACK_SIZE 20
#define MAX_PATH_LEN 4096
#define MAX_LS_BUFFER 16384
#define MAX_COMMAND_LEN 512
#define MAX_COMPONENTS 256
#define MAX_ENTRY_LEN 256  // 单个目录条目最大长度


typedef struct {
    char current_dir[MAX_PATH_LEN];   // 当前工作目录（相对根目录的绝对路径）
    char root_dir[MAX_PATH_LEN];      // 沙箱根目录（绝对路径）
    char *dir_stack[MAX_STACK_SIZE];  // 目录历史堆栈
    int stack_top;                    // 栈顶指针
} ClientSession;

// ====================== 辅助函数 ======================
// 安全字符串复制
void safe_strncpy(char *dest, const char *src, size_t n) {
    if (n == 0) return;
    size_t len = strnlen(src, n - 1);
    memcpy(dest, src, len);
    dest[len] = '\0';
}

// 安全连接字符串
void safe_strncat(char *dest, const char *src, size_t max_len) {
    size_t current_len = strlen(dest);
    size_t src_len = strlen(src);
    size_t avail = max_len - current_len - 1;
    
    if (avail > 0 && src_len > 0) {
        size_t copy_len = (src_len < avail) ? src_len : avail;
        strncat(dest, src, copy_len);
    }
}

// 确保路径以斜杠结尾
void ensure_trailing_slash(char *path, size_t max_len) {
    size_t len = strlen(path);
    if (len > 0 && path[len-1] != '/' && len < max_len - 1) {
        path[len] = '/';
        path[len+1] = '\0';
    }
}

// ====================== 路径处理 ======================
// 安全的路径拼接
bool safe_path_join(char *dest, size_t max_len, const char *base, const char *path) {
    size_t base_len = strlen(base);
    size_t path_len = strlen(path);
    
    // 确保有足够空间
    if (base_len + path_len + 2 > max_len) {
        return false;
    }
    
    strcpy(dest, base);
    
    // 添加分隔符（如果需要）
    if (base_len > 0 && dest[base_len-1] != '/' && path[0] != '/') {
        dest[base_len] = '/';
        dest[base_len+1] = '\0';
    }
    
    // 添加路径部分
    strcat(dest, path);
    return true;
}

// 路径规范化处理（修复版）
bool normalize_path(ClientSession *session, const char *input_path, char *output_path) {
    // 处理特殊路径
    if (strcmp(input_path, "~") == 0 || strcmp(input_path, "/") == 0) {
        safe_strncpy(output_path, session->root_dir, MAX_PATH_LEN);
        return true;
    }
    
    // 创建临时路径缓冲区
    char temp_path[MAX_PATH_LEN] = {0};
    
    // 处理绝对路径
    if (input_path[0] == '/') {
        if (!safe_path_join(temp_path, sizeof(temp_path), session->root_dir, input_path)) {
            return false;
        }
    } 
    // 处理相对路径
    else {
        if (!safe_path_join(temp_path, sizeof(temp_path), session->current_dir, input_path)) {
            return false;
        }
    }
    
    // 使用realpath获取规范路径
    char resolved_path[MAX_PATH_LEN];
    if (!realpath(temp_path, resolved_path)) {
        return false;
    }
    
    // 确保路径在沙箱内
    size_t root_len = strlen(session->root_dir);
    if (strncmp(resolved_path, session->root_dir, root_len) != 0) {
        return false;
    }
    
    // 返回相对于根目录的路径
    const char *relative_path = resolved_path + root_len;
    if (*relative_path == '\0') {
        strcpy(output_path, "/");
    } else {
        // 确保以斜杠开头
        if (relative_path[0] != '/') {
            snprintf(output_path, MAX_PATH_LEN, "/%s", relative_path);
        } else {
            safe_strncpy(output_path, relative_path, MAX_PATH_LEN);
        }
    }
    
    return true;
}

// ====================== 命令实现 ======================


// ====================== 命令实现 ======================
// 压栈：保存当前目录
bool push_dir(ClientSession *session) {
    if (session->stack_top >= MAX_STACK_SIZE) {
        return false;
    }
    
    session->dir_stack[session->stack_top] = strdup(session->current_dir);
    if (!session->dir_stack[session->stack_top]) {
        return false;
    }
    
    session->stack_top++;
    return true;
}

// 弹栈：获取历史目录
char *pop_dir(ClientSession *session) {
    if (session->stack_top <= 0) {
        return NULL;
    }
    
    session->stack_top--;
    char *dir = session->dir_stack[session->stack_top];
    session->dir_stack[session->stack_top] = NULL;
    return dir;
}


// 处理cd命令（修复警告版）
bool handle_cd(ClientSession *session, const char *path) {
    if (!path || path[0] == '\0') {
        path = "~";
    }
    
    // 特殊命令：cd - (返回上一级)
    if (strcmp(path, "-") == 0) {
        if (session->stack_top == 0) {
            return false;
        }
        
        char *prev_dir = pop_dir(session);
        if (!prev_dir) return false;
        
        if (!push_dir(session)) {
            free(prev_dir);
            return false;
        }
        
        safe_strncpy(session->current_dir, prev_dir, MAX_PATH_LEN);
        free(prev_dir);
        return true;
    }
    
    char target[MAX_PATH_LEN] = {0};
    
    // 规范化路径
    if (!normalize_path(session, path, target)) {
        return false;
    }

    // 构建绝对路径
    char absolute_path[MAX_PATH_LEN] = {0};
    if (!safe_path_join(absolute_path, sizeof(absolute_path), session->root_dir, target)) {
        return false;
    }
    
    // 验证路径存在
    struct stat st;
    if (stat(absolute_path, &st) != 0 || !S_ISDIR(st.st_mode)) {
        return false;
    }
    
    // 保存当前目录到堆栈
    if (!push_dir(session)) return false;
    
    // 更新当前目录（存储绝对路径）
    safe_strncpy(session->current_dir, absolute_path, MAX_PATH_LEN);
    ensure_trailing_slash(session->current_dir, MAX_PATH_LEN);
    
    return true;
}

// 处理ls命令（修复警告版）
char *handle_ls(ClientSession *session) {
    DIR *dir = opendir(session->current_dir);
    if (!dir) {
        return NULL;
    }

    char *result = (char *)calloc(MAX_LS_BUFFER, 1);
    if (!result) {
        closedir(dir);
        return NULL;
    }
    
    struct dirent *entry;
    size_t remaining = MAX_LS_BUFFER - 1;
    
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_name[0] == '.') continue;
        
        char type = ' ';
        if (entry->d_type == DT_DIR) type = '/';
        else if (entry->d_type == DT_LNK) type = '@';
        
        // 安全格式化
        char entry_str[MAX_ENTRY_LEN];
        int needed = snprintf(entry_str, sizeof(entry_str), "%-24.24s%c\n", 
                             entry->d_name, type);
        
        if (needed < 0 || (size_t)needed >= remaining) {
            break;
        }
        
        strcat(result, entry_str);
        remaining -= needed;
    }
    closedir(dir);
    
    if (strlen(result) == 0) {
        strcpy(result, "No files or directories\n");
    }
    
    return result;
}

// 处理mkdir命令（修复警告版）
bool handle_mkdir(ClientSession *session, const char *path) {
    if (!path || path[0] == '\0') {
        return false;
    }
    
    char relative_path[MAX_PATH_LEN] = {0};
    if (!normalize_path(session, path, relative_path)) {
        return false;
    }
    
    // 构建绝对路径
    char absolute_path[MAX_PATH_LEN] = {0};
    if (!safe_path_join(absolute_path, sizeof(absolute_path), 
                       session->root_dir, relative_path)) {
        return false;
    }
    
    // 移除尾部斜杠（如果需要）
    size_t len = strlen(absolute_path);
    if (len > 0 && absolute_path[len-1] == '/') {
        absolute_path[len-1] = '\0';
    }
    
    // 创建目录
    if (mkdir(absolute_path, 0700) != 0) {
        return false;
    }
    
    return true;
}

// 处理rmdir命令（修复警告版）
bool handle_rmdir(ClientSession *session, const char *path) {
    if (!path || path[0] == '\0') {
        return false;
    }
    
    char relative_path[MAX_PATH_LEN] = {0};
    if (!normalize_path(session, path, relative_path)) {
        return false;
    }
    
    // 构建绝对路径
    char absolute_path[MAX_PATH_LEN] = {0};
    if (!safe_path_join(absolute_path, sizeof(absolute_path), 
                       session->root_dir, relative_path)) {
        return false;
    }
    
    // 移除尾部斜杠（如果需要）
    size_t len = strlen(absolute_path);
    if (len > 0 && absolute_path[len-1] == '/') {
        absolute_path[len-1] = '\0';
    }
    
    // 删除目录
    if (rmdir(absolute_path) != 0) {
        return false;
    }
    
    return true;
}


// 处理pwd命令（修复版）
const char *handle_pwd(ClientSession *session) {
    static char result[MAX_PATH_LEN] = {0};
    
    // 获取相对于根目录的路径
    const char *relative = session->current_dir + strlen(session->root_dir);
    if (*relative == '\0') {
        strcpy(result, "/");
    } else {
        // 确保以斜杠开头
        if (relative[0] != '/') {
            snprintf(result, sizeof(result), "/%s", relative);
        } else {
            safe_strncpy(result, relative, MAX_PATH_LEN);
        }
    }
    
    // 移除尾部斜杠（根目录除外）
    size_t len = strlen(result);
    if (len > 1 && result[len-1] == '/') {
        result[len-1] = '\0';
    }
    
    return result;
}


// ====================== 命令处理器 ======================
void process_command(ClientSession *session, const char *command) {
    if (!command) return;
    
    // 解析命令
    char cmd[32] = {0};
    char path[MAX_COMMAND_LEN] = {0};  // 使用更大的缓冲区
    
    // 安全解析命令
    int args = sscanf(command, "%31s %511[^\n]", cmd, path);
    if (args < 1) {
        return;
    }
    
    // 清除可能的换行符
    size_t len = strlen(path);
    if (len > 0 && path[len-1] == '\n') {
        path[len-1] = '\0';
    }
    
    // 处理命令
    if (strcmp(cmd, "cd") == 0) {
        if (handle_cd(session, path)) {
            printf("CWD: %s\n", handle_pwd(session));
        } else {
            printf("ERROR: Directory change failed\n");
        }
    } 
    else if (strcmp(cmd, "pwd") == 0) {
        printf("Current directory: %s\n", handle_pwd(session));
    } 
    else if (strcmp(cmd, "ls") == 0) {
        char *list = handle_ls(session);
        if (list) {
            printf("%s", list);
            free(list);
        } else {
            printf("ERROR: Failed to list directory\n");
        }
    } 
    else if (strcmp(cmd, "mkdir") == 0) {
        if (handle_mkdir(session, path)) {
            printf("SUCCESS: Directory created\n");
        } else {
            printf("ERROR: Failed to create directory\n");
        }
    } 
    else if (strcmp(cmd, "rmdir") == 0) {
        if (handle_rmdir(session, path)) {
            printf("SUCCESS: Directory removed\n");
        } else {
            printf("ERROR: Failed to remove directory\n");
        }
    } 
    else {
        printf("ERROR: Unknown command '%s'\n", cmd);
    }
}


// ====================== 辅助函数 ======================
// 安全字符串复制
/* void safe_strncpy(char *dest, const char *src, size_t n) { */
/*     strncpy(dest, src, n-1); */
/*     dest[n-1] = '\0'; */
/* } */

// 确保路径以斜杠结尾
/* void ensure_trailing_slash(char *path) { */
/*     size_t len = strlen(path); */
/*     if (len > 0 && path[len-1] != '/' && len < MAX_PATH_LEN - 1) { */
/*         strcat(path, "/"); */
/*     } */
/* } */

// ====================== 会话管理 ======================
// 初始化会话
void init_session(ClientSession *session, const char *root) {
    memset(session, 0, sizeof(ClientSession));
    
    // 处理根目录
    if (!root) root = "/tmp/default_root";
    
    // 获取真实路径
    char real_root[MAX_PATH_LEN];
    if (realpath(root, real_root)) {
        safe_strncpy(session->root_dir, real_root, MAX_PATH_LEN);
    } else {
        safe_strncpy(session->root_dir, root, MAX_PATH_LEN);
    }
    
    // 确保以'/'结尾
    ensure_trailing_slash(session->root_dir,MAX_PATH_LEN);
    
    // 设置当前目录为根目录
    safe_strncpy(session->current_dir, session->root_dir, MAX_PATH_LEN);
    
    session->stack_top = 0;
}


// 清理会话资源
void free_session(ClientSession *session) {
    // 释放堆栈内存
    for (int i = 0; i < session->stack_top; i++) {
        if (session->dir_stack[i]) {
            free(session->dir_stack[i]);
            session->dir_stack[i] = NULL;
        }
    }
    session->stack_top = 0;
}


// ====================== 测试函数 ======================
int main() {
    const char *root_path = "/home/muridae/DraftsJ/TestsJ/Private_protocol_file_management_server_projectJ/PPFMSPJ/Tests1J/tmp/safe_root";
    
    ClientSession session;
    init_session(&session, root_path);
    
    printf("Root directory: %s\n", session.root_dir);
    printf("Current directory: %s\n", session.current_dir);
    
    // 创建测试环境
    mkdir(session.root_dir, 0700);
    chdir(session.root_dir);
    mkdir("documents", 0700);
    mkdir("projects", 0700);
    
    printf("\n=== Testing Commands ===\n");
    process_command(&session, "pwd");
    process_command(&session, "ls");
    process_command(&session, "cd documents");
    process_command(&session, "pwd");
    process_command(&session, "cd ..");
    process_command(&session, "pwd");
    process_command(&session, "mkdir new_folder");
    process_command(&session, "ls");
    process_command(&session, "rmdir new_folder");
    process_command(&session, "cd /");
    process_command(&session, "pwd");
    
    free_session(&session);
    return 0;
}
